//
//  ScreenRasterTransparentView.m
//  ScreenRaster_1
//
//  Created by Tianzhou on 08-10-31.
//  Copyright 2008 Tianzhou Software Inc.. All rights reserved.
// 
//   Licensed under the Apache License, Version 2.0 (the "License"); you may not
//   use this file except in compliance with the License.  You may obtain a copy
//   of the License at
//  
//   http://www.apache.org/licenses/LICENSE-2.0
// 
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
//   WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
//   License for the specific language governing permissions and limitations under
//   the License.
//

#import "ScreenRasterTransparentView.h"
#import	"ScreenRaster.h"
#import "ScreenRasterPreferenceKeys.h"

@interface ScreenRasterTransparentView(private_method)

- (BOOL)isShowPositionEnabled;
- (BOOL)isShowEdgeEnabled;
- (float)lineInterval;
- (float)lineWidth;
- (float)lineAlphaValue;
- (int)fontSize;
- (int)characterSpacing;

- (NSColor *)lineColor;
- (NSColor *)plotEdgeColor;
- (NSColor *)plotEdgeTextColor;
- (NSColor *)mousePointTextColor;
- (NSColor *)defaultColorNamed:(NSString *)colorName;


- (BOOL)shouldShowVerticalScreenRaster;
- (BOOL)shouldShowHorizontalScreenRaster;

- (void)beforeDrawRasterLineWithContext:(CGContextRef)theContext;
- (void)afterDrawRasterLineWithContext:(CGContextRef)theContext;
- (void)drawVerticalLineWithInterval:(float)theLineInterval;
- (void)drawHorizontalLineWithInterval:(float)theLineInterval;

- (void)beforeDrawPlotEdgeWithContext:(CGContextRef)theContext;
- (void)afterDrawPlotEdgeWithContext:(CGContextRef)theContext;
- (void)drawPlotEdge;

- (void)beforeDrawPlotEdgeTextWithContext:(CGContextRef)theContext;
- (void)afterDrawPlotEdgeTextWithContext:(CGContextRef)theContext;

- (void)drawEdgesWithFirstVertex:(NSPoint)firstVertex secondVertex:(NSPoint)secondVertex;

- (void)drawText:(NSString *)theText atPoint:(NSPoint)thePoint withContext:(CGContextRef)theContext;

- (NSPoint)convertViewToScreen:(NSPoint)viewPoint;
- (NSPoint)convertScreenToView:(NSPoint)screenPoint;


@end


@implementation ScreenRasterTransparentView(private_method)

- (BOOL)shouldShowVerticalScreenRaster
{
	NSUserDefaultsController *defaults = [NSUserDefaultsController sharedUserDefaultsController];
	id values = [defaults values];
	NSNumber *shouldShow = [values valueForKey:kScreenRasterShowVerticalRasterLineKey];
	return [shouldShow boolValue];
}

- (BOOL)shouldShowHorizontalScreenRaster
{
	NSUserDefaultsController *defaults = [NSUserDefaultsController sharedUserDefaultsController];
	id values = [defaults values];
	NSNumber *shouldShow = [values valueForKey:kScreenRasterShowHorizontalRasterLineKey];
	return [shouldShow boolValue];
}

- (BOOL)isShowPositionEnabled
{
	NSUserDefaultsController *defaults = [NSUserDefaultsController sharedUserDefaultsController];
	id values = [defaults values];
	NSNumber *shouldShow = [values valueForKey:kScreenRasterShowPositionKey];
	return [shouldShow boolValue];
}

- (BOOL)isShowEdgeEnabled
{
	NSUserDefaultsController *defaults = [NSUserDefaultsController sharedUserDefaultsController];
	id values = [defaults values];
	NSNumber *shouldShow = [values valueForKey:kScreenRasterShowEdgeKey];
	return [shouldShow boolValue];
}

- (float)lineInterval
{
	NSUserDefaultsController *defaults = [NSUserDefaultsController sharedUserDefaultsController];
	id values = [defaults values];
	NSNumber *theLineInterval = [values valueForKey:kScreenRasterLineIntervalKey];
	return [theLineInterval floatValue];
}

- (float)lineWidth
{
	NSUserDefaultsController *defaults = [NSUserDefaultsController sharedUserDefaultsController];
	id values = [defaults values];
	NSNumber *theLineWidth = [values valueForKey:kScreenRasterLineWidthKey];
	return [theLineWidth floatValue];
}

- (float)lineAlphaValue
{
	NSUserDefaultsController *defaults = [NSUserDefaultsController sharedUserDefaultsController];
	id values = [defaults values];
	NSNumber *theAlphaValue = [values valueForKey:kScreenRasterLineAlphaValueKey];
	return [theAlphaValue floatValue];
}

- (int)fontSize
{
	NSUserDefaultsController *defaults = [NSUserDefaultsController sharedUserDefaultsController];
	id values = [defaults values];
	NSNumber *theFontSize = [values valueForKey:kScreenRasterFontSizeKey];
	return [theFontSize intValue];
}

- (int)characterSpacing
{
	NSUserDefaultsController *defaults = [NSUserDefaultsController sharedUserDefaultsController];
	id values = [defaults values];
	NSNumber *theCharacterSpacing = [values valueForKey:kScreenRasterCharacterSpacingKey];
	return [theCharacterSpacing intValue];
}

- (NSColor *)defaultColorNamed:(NSString *)colorName
{
	NSColor *color = nil;
	NSUserDefaultsController *defaults = [NSUserDefaultsController sharedUserDefaultsController];
    id values = [defaults values];
    NSData *colorData = [values valueForKey:colorName];
    if (colorData) {
		color = (NSColor *)[NSUnarchiver unarchiveObjectWithData:colorData];
    }
	return color;
}

- (NSColor *)lineColor
{
	return [self defaultColorNamed:kScreenRasterLineColorKey];
}

- (NSColor *)plotEdgeColor
{
	return [self defaultColorNamed:kScreenRasterPlotEdgeColorKey];
}

- (NSColor *)plotEdgeTextColor
{
	return [self defaultColorNamed:kScreenRasterPlotEdgeTextColorKey];
}

- (NSColor *)mousePointTextColor
{
	return [self defaultColorNamed:kScreenRasterMousePointColorKey];
}

- (void)beforeDrawRasterLineWithContext:(CGContextRef)theContext
{
	NSColor *theColor = [self lineColor];
	CGContextSaveGState(theContext);
	[theColor set];
	CGContextSetAlpha(theContext, [self lineAlphaValue]);
	CGContextSetLineWidth(theContext,[self lineWidth]);
}

- (void)afterDrawRasterLineWithContext:(CGContextRef)theContext
{
	CGContextRestoreGState(theContext);
}

- (void)drawVerticalLineWithInterval:(float)theLineInterval
{
	float viewWidth = [self bounds].size.width;
	float viewHeight = [self bounds].size.height;
	
	float i;
	for (i = 0; i < viewWidth; i += theLineInterval)
	{
		NSRectFill(NSMakeRect(i,0,[self lineWidth],viewHeight));
	}
}

- (void)drawHorizontalLineWithInterval:(float)theLineInterval
{
	float viewWidth = [self bounds].size.width;
	float viewHeight = [self bounds].size.height;
	
	float i;
	for (i = 0; i < viewHeight; i += theLineInterval)
	{
		NSRectFill(NSMakeRect(0,i,viewWidth,[self lineWidth]));
	}
}

- (void)beforeDrawPlotEdgeWithContext:(CGContextRef)theContext
{
	const float dashLength[] = {4,1};
	CGContextSaveGState(theContext);
	CGContextSetAlpha(theContext, [self lineAlphaValue]);
	[[self plotEdgeColor] set];
	CGContextSetLineDash(theContext,0,dashLength,2);
}

- (void)afterDrawPlotEdgeWithContext:(CGContextRef)theContext
{
	CGContextRestoreGState(theContext);
}

- (void)drawPlotEdge
{
	switch (plotState_) {
		case kNoPoint:

			break;
		case kFirstPoint:
		{
			NSPoint thePoint = [self convertScreenToView:beginPoint_];
			
			CGContextRef theContext = [ [NSGraphicsContext currentContext] graphicsPort];
			
			CGContextSaveGState(theContext);
			[[self plotEdgeColor] set];
			
			CGContextAddEllipseInRect(theContext, CGRectMake(thePoint.x-1,thePoint.y-1,2,2));
			CGContextStrokePath(theContext);
			
			CGContextRestoreGState(theContext);
			break;
		}
		case kSecondPoint:
		{
			NSPoint thePoint1 = [self convertScreenToView:beginPoint_];
			NSPoint thePoint2 = [self convertScreenToView:endPoint_];
			
			CGContextRef theContext = [ [NSGraphicsContext currentContext] graphicsPort];
			
			CGContextSaveGState(theContext);
			[[self plotEdgeColor] set];
			CGContextSetLineWidth(theContext,[self lineWidth]);
			
			CGContextMoveToPoint(theContext,thePoint1.x,thePoint1.y);
			CGContextAddLineToPoint(theContext,thePoint2.x,thePoint2.y);
			CGContextStrokePath(theContext);
			
			CGContextRestoreGState(theContext);
			
			if([self isShowEdgeEnabled])
			{
				[self beforeDrawPlotEdgeWithContext:theContext];
				[self drawEdgesWithFirstVertex:thePoint1 
								  secondVertex:thePoint2];
				[self afterDrawPlotEdgeWithContext:theContext];
			}
		}
			break;
		default:
			break;
	}
}

- (void)beforeDrawPlotEdgeTextWithContext:(CGContextRef)theContext
{
	CGContextSaveGState(theContext);
	CGContextSetAlpha(theContext, 1);
	[[self plotEdgeTextColor] set];
}

- (void)afterDrawPlotEdgeTextWithContext:(CGContextRef)theContext
{
	CGContextRestoreGState(theContext);
}

- (void)drawEdgesWithFirstVertex:(NSPoint)firstVertex secondVertex:(NSPoint)secondVertex
{
	if (firstVertex.x == secondVertex.x
	   || firstVertex.y == secondVertex.y)
	{
		
	}
	else
	{
		NSPoint lowYPoint,highYPoint;
		if( firstVertex.y<secondVertex.y )
		{
			lowYPoint = firstVertex;
			highYPoint = secondVertex;
		}
		else
		{
			lowYPoint = secondVertex;
			highYPoint = firstVertex;
		}
	
		CGContextRef theContext = [ [NSGraphicsContext currentContext] graphicsPort];
		
		CGContextSaveGState(theContext);
		CGContextSetLineWidth(theContext,[self lineWidth]);
		CGContextMoveToPoint(theContext,lowYPoint.x,lowYPoint.y);
		CGContextAddLineToPoint(theContext,highYPoint.x,lowYPoint.y);
		CGContextMoveToPoint(theContext,highYPoint.x,lowYPoint.y);
		CGContextAddLineToPoint(theContext,highYPoint.x,highYPoint.y);
		CGContextStrokePath(theContext);
		CGContextRestoreGState(theContext);
		
		[self beforeDrawPlotEdgeTextWithContext:theContext];

		NSString *theString = [NSString stringWithFormat:@"%d",abs(lowYPoint.x - highYPoint.x)];
		[self drawText:theString 
			   atPoint:NSMakePoint((lowYPoint.x + highYPoint.x) / 2, lowYPoint.y - [self fontSize])
		   withContext:theContext];

		theString = [NSString stringWithFormat:@"%d",abs(lowYPoint.y - highYPoint.y)];
		// [TODO] What I really want to do is center the text, however I don't know how
		// to get the total width of the text in pixel.
		[self drawText:theString 
			   atPoint:NSMakePoint(highYPoint.x + [theString length], (lowYPoint.y + highYPoint.y - [self fontSize]) / 2)
		   withContext:theContext];
		
		[self afterDrawPlotEdgeTextWithContext:theContext];
	}
}

- (void)drawText:(NSString *)theText atPoint:(NSPoint)thePoint withContext:(CGContextRef)theContext
{
	CGContextSetTextMatrix(theContext, CGAffineTransformIdentity);
	CGContextSelectFont (theContext,
						 "Times-Bold",
						 [self fontSize],
						 kCGEncodingMacRoman);
	CGContextSetCharacterSpacing(theContext, [self characterSpacing]);
	CGContextSetTextDrawingMode(theContext,kCGTextFill);
	CGContextShowTextAtPoint(theContext,
							 thePoint.x,
							 thePoint.y,
							 [theText cStringUsingEncoding:NSASCIIStringEncoding],
							 [theText length]);
	CGContextStrokePath(theContext);
}
						
- (NSPoint)convertViewToScreen:(NSPoint)viewPoint
{
	NSPoint thePoint = [self convertPointToBase:viewPoint];
	return [[self window] convertBaseToScreen:thePoint];
}
						
- (NSPoint)convertScreenToView:(NSPoint)screenPoint
{
	NSPoint thePoint = [self convertViewToScreen:NSMakePoint(0,0)];
	return NSMakePoint(screenPoint.x-thePoint.x,screenPoint.y-thePoint.y);
}


@end

@implementation ScreenRasterTransparentView

- (id)initWithFrame:(NSRect)theRect
{
	if (self = [super initWithFrame:theRect])
	{
		shouldShowVerticalScreenRaster_ = YES;
		shouldShowHorizontalScreenRaster_ = YES;
	}
	return self;
}

// In order to receive mouseMove event
- (BOOL)acceptsFirstResponder
{
	return YES;
}

- (BOOL)isFlipped
{
	return NO;
}

- (void)drawRect:(NSRect)theRect
{
	
#if DEBUG_MODE
	[[NSColor colorWithCalibratedWhite:1 alpha:0.5] set];
#else
	[[NSColor colorWithCalibratedWhite:1 alpha:0.1] set];
#endif	
	
	NSRectFill(theRect);
	
	CGContextRef theContext = [[NSGraphicsContext currentContext] graphicsPort];
	
	if ([self shouldShowVerticalScreenRaster] || [self shouldShowHorizontalScreenRaster])
	{
		[self beforeDrawRasterLineWithContext:theContext];
	}
	
	if([self shouldShowVerticalScreenRaster])
	{
		[self drawVerticalLineWithInterval:[self lineInterval] ];
	}
	if([self shouldShowHorizontalScreenRaster])
	{
		[self drawHorizontalLineWithInterval:[self lineInterval] ];
	}
	
	if ([self shouldShowVerticalScreenRaster] || [self shouldShowHorizontalScreenRaster])
	{
		[self afterDrawRasterLineWithContext:theContext];
	}
	
	
	if([self isShowPositionEnabled])
	{
		
		CGContextSaveGState(theContext);
		
		[[self mousePointTextColor] set];
		
		NSString *theString = [NSString stringWithFormat:@"X:%f Y:%f",basePoint_.x,basePoint_.y];
		[self drawText:theString
			   atPoint:viewPoint_
		   withContext:theContext];

		CGContextRestoreGState(theContext);
	}

	[self drawPlotEdge];
}

- (void)mouseDown:(NSEvent *)theEvent
{
	NSPoint thePoint = [ [self window] convertBaseToScreen:[theEvent locationInWindow] ];
	switch (plotState_) {
		case kNoPoint:
			beginPoint_ = thePoint;
			plotState_ = kFirstPoint;
			break;
		case kFirstPoint:
			endPoint_ = thePoint;
			plotState_ = kSecondPoint;
			break;
		case kSecondPoint:
			plotState_ = kNoPoint;
			break;
		default:
			break;
	}
	[self display];
}

- (void)mouseMoved:(NSEvent *)theEvent
{
	if ( [theEvent window] )
	{
		viewPoint_ = [self convertPoint:[theEvent locationInWindow] fromView:nil];
		basePoint_ = [ [self window] convertBaseToScreen:[theEvent locationInWindow] ];
	}
	else
	{
		viewPoint_ = [self convertPointFromBase:[theEvent locationInWindow] ];
		basePoint_ = [theEvent locationInWindow];
	}
	[self display];
}

@end
